#include "depslib.h"
#include "jam.h"
#include "hash.h"
#include "lists.h"
#include "headers.h"
#include "newstr.h"
#include "pathsys.h"
#include "pathsplit.h"
#include "search.h"
#include "timestamp.h"
#include "cache.h"

#define DEPS_STATE_INIT 0x0001
#define DEPS_STATE_DONE 0x0002
#define DEPS_STATE_SEARCH 0x0004

struct depsStats g_stats;
static int g_state = 0;
static int s_error = 0;

static int inState( int state ) {
  return ( g_state & state ) == state;
}

static void setErr( int error ) {
  s_error = error;
}

void depsStart( void ) {
  if( inState( DEPS_STATE_INIT ) ) {
    setErr( DEPS_ERROR_ALREADY_INIT );
    return;
  }
  setErr( 0 );
  memset( ( char * ) &g_stats, 0, sizeof( g_stats ) );
  g_state |= DEPS_STATE_INIT;
}

void depsSetCWD( const char *cwd ) {
  if( !inState( DEPS_STATE_INIT ) ) {
    setErr( DEPS_ERROR_NOT_INIT );
    return;
  }
  setErr( 0 );
  path_setcwd( cwd );
}

void depsSearchStart( void ) {
  if( !inState( DEPS_STATE_INIT ) ) {
    setErr( DEPS_ERROR_NOT_INIT );
    return;
  }
  search_init();
  g_state |= DEPS_STATE_SEARCH;
  setErr( 0 );
}

void depsAddSearchDir( const char *path ) {
  if( !inState( DEPS_STATE_INIT | DEPS_STATE_SEARCH ) ) {
    if( !inState( DEPS_STATE_SEARCH ) ) {
      setErr( DEPS_ERROR_NOT_SEARCH );
    }
    if( !inState( DEPS_STATE_INIT ) ) {
      setErr( DEPS_ERROR_NOT_INIT );
    }
    return;
  }
  setErr( 0 );
  search_adddir( path );
}

depsRef depsScanForHeaders( const char *path ) {
  PATHSPLIT f;
  char buf[MAXJPATH];
  time_t time;
  HEADER *h;
  if( !inState( DEPS_STATE_INIT | DEPS_STATE_SEARCH ) ) {
    if( !inState( DEPS_STATE_SEARCH ) ) {
      setErr( DEPS_ERROR_NOT_SEARCH );
    }
    if( !inState( DEPS_STATE_INIT ) ) {
      setErr( DEPS_ERROR_NOT_INIT );
    }
    return NULL;
  }
  setErr( 0 );
  path_split( path, &f );
  path_normalize( &f, NULL );
  path_tostring( &f, buf );
  timestamp( buf, &time );
  if( !time ) {
    return NULL;
  }
  h = headers( buf, time );
  return ( depsRef ) h;
}

const char *depsGetNewest( depsRef ref, time_t *time ) {
  HEADER *h = ( HEADER * )ref;
  headernewest( h );
  *time = h->newest->time;
  return h->newest->key;
}

void depsTimeStamp( const char *path, time_t *time ) {
  PATHSPLIT f;
  char buf[MAXJPATH];
  if( !inState( DEPS_STATE_INIT ) ) {
    setErr( DEPS_ERROR_NOT_INIT );
    return;
  }
  setErr( 0 );
  path_split( path, &f );
  path_normalize( &f, NULL );
  path_tostring( &f, buf );
  timestamp( buf, time );
}

void depsGetStats( struct depsStats *stats ) {
  if( !inState( DEPS_STATE_INIT ) ) {
    setErr( DEPS_ERROR_NOT_INIT );
    return;
  }
  setErr( 0 );
  *stats = g_stats;
}

void depsCacheRead( const char *path ) {
  cache_read( path );
}

void depsCacheWrite( const char *path ) {
  cache_write( path );
}

void depsDone( void ) {
  if( !inState( DEPS_STATE_INIT ) ) {
    setErr( DEPS_ERROR_NOT_INIT );
    return;
  }
  setErr( 0 );
  donestamps();
  donestr();
  donelist();
  donehdrs();
  donesearch();
  donepath();
  donecache();
  g_state = DEPS_STATE_DONE;
}

int depsError( void ) {
  return s_error;
}
